<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI对话 - Telchina.AI</title>
    <link href="./assets/index.css" rel="stylesheet">
    <script src="./assets/plotly-latest.min.js" type="text/javascript"></script>
    <script src="./js/tailwind.min.js"></script>
    <script src="./assets/auth.js"></script>
    <script src="./assets/api-client.js"></script>
    <link rel="icon" type="image/svg+xml" href="./vanna.svg" />
    <style>

    </style>
</head>
<body class="bg-gray-50 dark:bg-gray-900">
    <div class="min-h-screen flex flex-col pt-16">
        <!-- 顶部导航 -->
        <nav class="fixed top-0 left-0 right-0 z-50 bg-white dark:bg-gray-800 shadow-sm border-b border-gray-200 dark:border-gray-700">
            <div class="w-full px-4 sm:px-6 lg:px-8">
                <div class="flex justify-between h-16">
                    <div class="flex items-center">
                        <img src="./telchina.svg" alt="Telchina.AI" class="h-8 w-8 mr-3">
                        <h1 class="text-xl font-semibold text-gray-900 dark:text-white">AI对话助手</h1>
                    </div>
                    <div class="flex items-center space-x-4">
                        <a href="index.html" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg font-medium flex items-center">
                            <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
                            </svg>
                            返回首页
                        </a>
                        <a href="training.html" class="text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white px-3 py-2 rounded-md text-sm font-medium">训练SQL</a>
                        <a href="templates.html" class="text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white px-3 py-2 rounded-md text-sm font-medium">SQL模板</a>
                        <a href="dashboard.html" class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 px-3 py-2 rounded-md text-sm font-medium flex items-center">
                            <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
                            </svg>
                            仪表板
                        </a>
                        <button id="darkModeToggle" class="p-2 rounded-md text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white">
                            <!-- 浅色模式图标 (全月) -->
                            <svg id="lightModeIcon" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>
                            </svg>
                            <!-- 暗黑模式图标 (半月) -->
                            <svg id="darkModeIcon" class="w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
                            </svg>
                        </button>
                    </div>
                </div>
            </div>
        </nav>

        <!-- 主要内容区域 -->
        <div class="flex-1 flex">
            <!-- 侧边栏 -->
            <div id="sidebar" class="w-64 bg-white dark:bg-gray-800 shadow-sm border-r border-gray-200 dark:border-gray-700 transition-all duration-300 ease-in-out relative group">
                <!-- 收起侧边栏按钮 - 悬浮在边框上，鼠标悬停时显示 -->
                <button id="sidebarToggle" class="absolute -right-3 top-1/2 -translate-y-1/2 z-10 w-6 h-6 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-full shadow-md text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center justify-center transition-all duration-300 opacity-0 group-hover:opacity-100">
                    <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
                    </svg>
                </button>
                <div class="p-4">
                    <button id="newChatBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg flex items-center justify-center space-x-2">
                        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
                        </svg>
                        <span>新对话</span>
                    </button>
                </div>
                <div class="px-4 pb-4">
                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">历史对话</h3>
                    <div id="chatHistory" class="space-y-1">
                        <!-- 历史对话列表 -->
                    </div>
                </div>
            </div>

            <!-- 聊天区域 -->
            <div id="chatArea" class="flex-1 flex flex-col transition-all duration-300 ease-in-out">
                <!-- 消息区域 -->
                <div id="messagesContainer" class="flex-1 overflow-y-auto p-2 space-y-4" style="padding-left: 0; padding-right: 0;">
                    <div class="text-center text-gray-500 dark:text-gray-400 mt-20">
                        <svg class="w-16 h-16 mx-auto mb-4 text-gray-300 dark:text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
                        </svg>
                        <p class="text-lg font-medium">开始新的对话</p>
                        <p class="text-sm">输入您的问题，我将为您生成SQL查询并执行</p>
                    </div>
                </div>

                <!-- 输入区域 -->
                <div class="border-t border-gray-200 dark:border-gray-700 p-4">
                    <div class="flex space-x-4">
                        <div class="flex-1">
                            <textarea id="questionInput" 
                                    placeholder="请输入您的问题..." 
                                    class="w-full p-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-700 dark:text-white resize-none"
                                    rows="2"></textarea>
                        </div>
                        <button id="sendBtn" 
                                class="bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-medium py-2 px-6 rounded-lg transition-colors">
                            <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
                            </svg>
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        class ChatApp {
            constructor() {
                this.currentChatId = null;
                this.isLoading = false;
                this.initializeElements();
                this.bindEvents();
                this.loadChatHistory();
                this.initializeDarkMode();
                this.initializeSidebar();
            }

            initializeElements() {
                this.messagesContainer = document.getElementById('messagesContainer');
                this.questionInput = document.getElementById('questionInput');
                this.sendBtn = document.getElementById('sendBtn');
                this.newChatBtn = document.getElementById('newChatBtn');
                this.chatHistory = document.getElementById('chatHistory');
                this.darkModeToggle = document.getElementById('darkModeToggle');
                this.sidebarToggle = document.getElementById('sidebarToggle');
                this.sidebar = document.getElementById('sidebar');
                this.chatArea = document.getElementById('chatArea');
            }

            bindEvents() {
                this.sendBtn.addEventListener('click', () => this.sendMessage());
                this.questionInput.addEventListener('keypress', (e) => {
                    if (e.key === 'Enter' && !e.shiftKey) {
                        e.preventDefault();
                        this.sendMessage();
                    }
                });
                this.newChatBtn.addEventListener('click', () => this.startNewChat());
                this.darkModeToggle.addEventListener('click', () => this.toggleDarkMode());
                this.sidebarToggle.addEventListener('click', () => this.toggleSidebar());
                

            }

            updateThemeIcon(isDark) {
                const lightIcon = document.getElementById('lightModeIcon');
                const darkIcon = document.getElementById('darkModeIcon');
                
                if (isDark) {
                    // 暗黑模式：显示半月图标
                    lightIcon.classList.add('hidden');
                    darkIcon.classList.remove('hidden');
                } else {
                    // 浅色模式：显示全月图标
                    lightIcon.classList.remove('hidden');
                    darkIcon.classList.add('hidden');
                }
            }

            initializeDarkMode() {
                const isDark = localStorage.getItem('darkMode') === 'true';
                if (isDark) {
                    document.documentElement.classList.add('dark');
                }
                this.updateThemeIcon(isDark);
            }

            initializeSidebar() {
                const isHidden = localStorage.getItem('sidebarHidden') === 'true';
                if (isHidden) {
                    this.sidebar.classList.remove('w-64');
                    this.sidebar.classList.add('hidden', '-ml-64');
                    this.showShowButton();
                }
            }

            toggleDarkMode() {
                const isDark = document.documentElement.classList.toggle('dark');
                localStorage.setItem('darkMode', isDark.toString());
                this.updateThemeIcon(isDark);
            }

            toggleSidebar() {
                const isHidden = this.sidebar.classList.contains('hidden');
                if (isHidden) {
                    // 显示侧边栏
                    this.sidebar.classList.remove('hidden', '-ml-64');
                    this.sidebar.classList.add('w-64');
                    this.hideShowButton();
                } else {
                    // 隐藏侧边栏
                    this.sidebar.classList.remove('w-64');
                    this.sidebar.classList.add('hidden', '-ml-64');
                    this.showShowButton();
                }
                
                // 保存状态到localStorage
                localStorage.setItem('sidebarHidden', !isHidden);
            }

            showShowButton() {
                // 创建显示侧边栏的按钮
                if (!document.getElementById('showSidebarBtn')) {
                    const showBtn = document.createElement('button');
                    showBtn.id = 'showSidebarBtn';
                    showBtn.className = 'fixed top-20 left-4 z-50 p-2 bg-white dark:bg-gray-800 rounded-md shadow-lg border border-gray-200 dark:border-gray-700 text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-700';
                    showBtn.innerHTML = `
                        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
                        </svg>
                    `;
                    showBtn.addEventListener('click', () => this.toggleSidebar());
                    document.body.appendChild(showBtn);
                }
            }

            hideShowButton() {
                const showBtn = document.getElementById('showSidebarBtn');
                if (showBtn) {
                    showBtn.remove();
                }
            }

            async sendMessage() {
                const question = this.questionInput.value.trim();
                if (!question || this.isLoading) return;

                this.isLoading = true;
                this.updateSendButton(true);
                this.questionInput.value = '';

                // 添加用户消息
                this.addMessage('user', question);
                
                // 添加加载指示器
                const loadingId = this.addLoadingMessage();

                try {
                    // 生成SQL
                    await this.generateSQL(question, loadingId);
                } catch (error) {
                    this.removeLoadingMessage(loadingId);
                    this.addMessage('error', '抱歉，处理您的请求时出现错误。');
                } finally {
                    this.isLoading = false;
                    this.updateSendButton(false);
                }
            }

            async generateSQL(question, loadingId) {
                // 使用流式调用
                const useStream = true; // 可以改为配置项
                
                if (useStream) {
                    await this.generateSQLStream(question, loadingId);
                } else {
                    // 原有的非流式调用
                    const response = await authenticatedFetch(`/api/v0/generate_sql?question=${encodeURIComponent(question)}${this.currentChatId ? `&id=${this.currentChatId}` : ''}`);
                    const data = await response.json();

                    this.removeLoadingMessage(loadingId);

                    if (data.type === 'error') {
                        this.addMessage('error', data.error);
                        return;
                    }

                    this.currentChatId = data.id;
                    this.addMessage('sql', data.text);

                    // 执行SQL
                    await this.runSQL(data.id);
                }
            }

            async generateSQLStream(question, loadingId) {
                try {
                    const url = `/api/v0/generate_sql`;
                    const body = {
                        question: question,
                        stream: true,
                        id: this.currentChatId
                    };

                    const response = await authenticatedFetch(url, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(body)
                    });

                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }

                    const reader = response.body.getReader();
                    const decoder = new TextDecoder();
                    let buffer = '';
                    let sqlChunks = [];
                    let sqlMessageElement = null;
                    let finalSQL = '';

                    while (true) {
                        const { done, value } = await reader.read();
                        
                        if (done) break;

                        buffer += decoder.decode(value, { stream: true });
                        const lines = buffer.split('\n\n');
                        buffer = lines.pop() || '';

                        for (const line of lines) {
                            if (!line.trim() || !line.startsWith('data: ')) continue;

                            try {
                                const data = JSON.parse(line.slice(6));

                                if (data.type === 'id') {
                                    this.currentChatId = data.id;
                                    this.removeLoadingMessage(loadingId);
                                    
                                } else if (data.type === 'template') {
                                    // 模板SQL直接显示
                                    finalSQL = data.sql;
                                    this.addMessage('sql', finalSQL);
                                    
                                } else if (data.type === 'chunk') {
                                    // 流式SQL片段
                                    sqlChunks.push(data.text);
                                    
                                    if (!sqlMessageElement) {
                                        // 创建SQL消息容器
                                        sqlMessageElement = this.addStreamingSQLMessage();
                                    }
                                    
                                    // 更新显示的SQL
                                    this.updateStreamingSQLMessage(sqlMessageElement, sqlChunks.join(''));
                                    
                                } else if (data.type === 'complete') {
                                    // SQL生成完成
                                    finalSQL = data.sql;
                                    
                                    if (sqlMessageElement) {
                                        // 更新为最终SQL
                                        this.finalizeStreamingSQLMessage(sqlMessageElement, finalSQL);
                                    }
                                    
                                } else if (data.type === 'error') {
                                    this.removeLoadingMessage(loadingId);
                                    this.addMessage('error', data.error);
                                    return;
                                }
                            } catch (e) {
                                console.error('解析SSE数据失败:', e, line);
                            }
                        }
                    }

                    // 执行SQL
                    if (finalSQL && this.currentChatId) {
                        await this.runSQL(this.currentChatId);
                    }

                } catch (error) {
                    console.error('流式生成SQL失败:', error);
                    this.removeLoadingMessage(loadingId);
                    this.addMessage('error', '生成SQL时出现错误: ' + error.message);
                }
            }

            addStreamingSQLMessage() {
                // 清除欢迎消息
                const welcomeMsg = this.messagesContainer.querySelector('.text-center');
                if (welcomeMsg) {
                    welcomeMsg.remove();
                }

                const messageDiv = document.createElement('div');
                messageDiv.className = 'flex justify-start mb-4 mx-2 streaming-sql-message';

                const messageContainer = document.createElement('div');
                messageContainer.className = 'flex flex-col items-start max-w-4xl';

                // 头像和时间戳
                const headerDiv = document.createElement('div');
                headerDiv.className = 'flex items-center mb-1 flex-row';
                
                const avatar = document.createElement('div');
                avatar.className = 'w-8 h-8 rounded-full flex items-center justify-center text-white text-sm font-medium bg-gray-600 mr-2';
                avatar.textContent = 'AI';
                
                const timestamp = document.createElement('span');
                timestamp.className = 'text-xs text-gray-500 dark:text-gray-400';
                timestamp.textContent = new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
                
                headerDiv.appendChild(avatar);
                headerDiv.appendChild(timestamp);

                // 内容区域
                const contentDiv = document.createElement('div');
                contentDiv.className = 'px-4 py-3 rounded-lg shadow-sm bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-bl-sm';
                contentDiv.innerHTML = `
                    <div class="flex items-center justify-between mb-3">
                        <div class="flex items-center space-x-2">
                            <svg class="w-5 h-5 text-green-600 dark:text-green-400 animate-pulse" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                            </svg>
                            <span class="text-sm font-medium text-gray-700 dark:text-gray-300">正在生成SQL查询...</span>
                        </div>
                    </div>
                    <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                        <pre class="text-sm overflow-x-auto sql-content"><code class="language-sql"></code></pre>
                    </div>
                `;

                messageContainer.appendChild(headerDiv);
                messageContainer.appendChild(contentDiv);
                messageDiv.appendChild(messageContainer);
                
                this.messagesContainer.appendChild(messageDiv);
                this.scrollToBottom();
                
                return messageDiv;
            }

            updateStreamingSQLMessage(messageElement, sqlText) {
                const codeElement = messageElement.querySelector('.sql-content code');
                if (codeElement) {
                    codeElement.textContent = sqlText;
                }
                this.scrollToBottom();
            }

            finalizeStreamingSQLMessage(messageElement, finalSQL) {
                const contentDiv = messageElement.querySelector('.px-4');
                if (contentDiv) {
                    contentDiv.innerHTML = `
                        <div class="flex items-center justify-between mb-3">
                            <div class="flex items-center space-x-2">
                                <svg class="w-5 h-5 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                                </svg>
                                <span class="text-sm font-medium text-gray-700 dark:text-gray-300">生成的SQL查询</span>
                            </div>
                            <button class="copy-sql-btn text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 flex items-center space-x-1" data-sql="${this.escapeHtml(finalSQL).replace(/"/g, '&quot;')}">
                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
                                </svg>
                                <span>复制</span>
                            </button>
                        </div>
                        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                            <pre class="text-sm overflow-x-auto"><code class="language-sql">${this.escapeHtml(finalSQL)}</code></pre>
                        </div>
                    `;
                    
                    // 重新绑定复制按钮事件
                    const copyBtn = contentDiv.querySelector('.copy-sql-btn');
                    if (copyBtn) {
                        copyBtn.addEventListener('click', () => {
                            const sql = copyBtn.getAttribute('data-sql');
                            this.copyToClipboard(sql);
                        });
                    }
                }
                messageElement.classList.remove('streaming-sql-message');
            }

            async runSQL(id) {
                const response = await authenticatedFetch(`/api/v0/run_sql?id=${id}`);
                const data = await response.json();

                if (data.type === 'error') {
                    this.addMessage('error', data.error);
                    // 即使出错也要刷新历史记录
                    this.loadChatHistory();
                    return;
                }

                const df = JSON.parse(data.df);
                this.addMessage('table', df);

                // 生成图表
                await this.generateChart(id);
            }

            async generateChart(id) {
                try {
                    const isDark = document.documentElement.classList.contains('dark');
                    const response = await authenticatedFetch(`/api/v0/generate_plotly_figure?id=${id}&dark_mode=${isDark}`);
                    const data = await response.json();

                    if (data.type === 'plotly_figure') {
                        this.addMessage('chart', JSON.parse(data.fig));
                    }
                } catch (error) {
                    console.log('图表生成失败:', error);
                } finally {
                    // 对话完成后刷新历史记录
                    this.loadChatHistory();
                }
            }

            addMessage(type, content) {
                // 清除欢迎消息（在添加第一条消息时）
                const welcomeMsg = this.messagesContainer.querySelector('.text-center');
                if (welcomeMsg) {
                    welcomeMsg.remove();
                }

                const messageDiv = document.createElement('div');
                const marginClass = type === 'chart' ? 'mx-0' : 'mx-2';
                messageDiv.className = 'flex ' + (type === 'user' ? 'justify-end' : 'justify-start') + ' mb-4 ' + marginClass;

                // 创建消息容器
                const messageContainer = document.createElement('div');
                const maxWidth = type === 'chart' ? 'w-full' : 'max-w-4xl';
                messageContainer.className = 'flex flex-col ' + (type === 'user' ? 'items-end' : 'items-start') + ' ' + maxWidth;

                // 添加头像和时间戳
                const headerDiv = document.createElement('div');
                headerDiv.className = 'flex items-center mb-1 ' + (type === 'user' ? 'flex-row-reverse' : 'flex-row');
                
                const avatar = document.createElement('div');
                avatar.className = `w-8 h-8 rounded-full flex items-center justify-center text-white text-sm font-medium ${
                    type === 'user' ? 'bg-blue-600 ml-2' : 'bg-gray-600 mr-2'
                }`;
                avatar.textContent = type === 'user' ? '我' : 'AI';
                
                const timestamp = document.createElement('span');
                timestamp.className = 'text-xs text-gray-500 dark:text-gray-400';
                timestamp.textContent = new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
                
                headerDiv.appendChild(avatar);
                headerDiv.appendChild(timestamp);

                // 创建内容区域
                const contentDiv = document.createElement('div');
                contentDiv.className = `px-4 py-3 rounded-lg shadow-sm ${
                    type === 'user' 
                        ? 'bg-blue-600 text-white rounded-br-sm' 
                        : type === 'error'
                        ? 'bg-red-50 text-red-800 border border-red-200 dark:bg-red-900/20 dark:text-red-200 dark:border-red-800 rounded-bl-sm'
                        : 'bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-bl-sm'
                }`;

                if (type === 'user') {
                    contentDiv.innerHTML = `<div class="whitespace-pre-wrap">${this.escapeHtml(content)}</div>`;
                } else if (type === 'sql') {
                    contentDiv.innerHTML = `
                        <div class="flex items-center justify-between mb-3">
                            <div class="flex items-center space-x-2">
                                <svg class="w-5 h-5 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                                </svg>
                                <span class="text-sm font-medium text-gray-700 dark:text-gray-300">生成的SQL查询</span>
                            </div>
                            <button class="copy-sql-btn text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 flex items-center space-x-1" data-sql="${content.replace(/"/g, '&quot;')}">
                                 <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                     <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
                                 </svg>
                                 <span>复制</span>
                             </button>
                        </div>
                        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                            <pre class="text-sm overflow-x-auto"><code class="language-sql">${this.escapeHtml(content)}</code></pre>
                        </div>
                    `;
                } else if (type === 'table') {
                    contentDiv.innerHTML = this.createTable(content);
                } else if (type === 'chart') {
                    const chartId = 'chart_' + Date.now();
                    contentDiv.innerHTML = `
                        <div class="flex items-center justify-between mb-3">
                            <div class="flex items-center space-x-2">
                                <svg class="w-5 h-5 text-purple-600 dark:text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
                                </svg>
                                <span class="text-sm font-medium text-gray-700 dark:text-gray-300">数据可视化</span>
                            </div>
                            <div class="flex items-center space-x-2">
                                <button class="save-chart-btn text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 flex items-center space-x-1" data-chart-id="${chartId}" data-chart-data='${JSON.stringify(content).replace(/'/g, "&apos;")}'>
                                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3-3m0 0l-3 3m3-3v12"></path>
                                    </svg>
                                    <span>保存到仪表板</span>
                                </button>
                                <button class="chart-download-btn text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 flex items-center space-x-1" data-chart-id="${chartId}">
                                    <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
                                    </svg>
                                    <span>下载</span>
                                </button>
                            </div>
                        </div>
                        <div class="chart-container" style="position: relative; width: 100%; max-width: 1200px; margin: 0 auto; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);" class="bg-white dark:bg-gray-800">
                            <div id="${chartId}" style="width: 100%; height: 600px;" class="bg-white dark:bg-gray-800"></div>
                        </div>
                    `;
                    setTimeout(() => {
                        // 优化的Plotly配置
                        const config = {
                            responsive: true,
                            displayModeBar: true,
                            displaylogo: false,
                            modeBarButtonsToAdd: [
                                {
                                    name: '自适应大小',
                                    icon: Plotly.Icons.autoscale,
                                    click: function(gd) {
                                        Plotly.relayout(gd, {
                                            'xaxis.autorange': true,
                                            'yaxis.autorange': true
                                        });
                                    }
                                }
                            ],
                            modeBarButtonsToRemove: ['lasso2d', 'select2d']
                        };
                        
                        // 检测当前暗黑模式状态
                        const isDarkMode = document.documentElement.classList.contains('dark');
                        
                        // 根据暗黑模式设置颜色
                        const colors = isDarkMode ? {
                            font: '#e5e7eb',
                            background: '#1f2937',
                            paper: '#1f2937',
                            grid: '#374151'
                        } : {
                            font: '#374151',
                            background: '#ffffff',
                            paper: '#ffffff',
                            grid: '#e5e7eb'
                        };
                        
                        // 优化布局配置
                        const layout = {
                            ...content.layout,
                            autosize: true,
                            height: 580,
                            width: 1200, // 使用固定宽度1200px
                            margin: { l: 15, r: 15, t: 60, b: 80 },
                            font: { size: 14, color: colors.font },
                            showlegend: true,
                            legend: {
                                orientation: 'h',
                                y: -0.12,
                                x: 0.5,
                                xanchor: 'center',
                                font: { color: colors.font }
                            },
                            plot_bgcolor: colors.background,
                            paper_bgcolor: colors.paper,
                            xaxis: {
                                ...content.layout.xaxis,
                                gridcolor: colors.grid,
                                tickfont: { color: colors.font },
                                titlefont: { color: colors.font }
                            },
                            yaxis: {
                                ...content.layout.yaxis,
                                gridcolor: colors.grid,
                                tickfont: { color: colors.font },
                                titlefont: { color: colors.font }
                            }
                        };
                        
                        // 获取容器实际宽度
                        const container = document.getElementById(chartId);
                        
                        // 让图表自动适应容器宽度
                        setTimeout(() => {
                            layout.width = undefined;
                        }, 50);
                        
                        Plotly.newPlot(chartId, content.data, layout, config);
                        
                        // 监听窗口大小变化
                        window.addEventListener('resize', () => {
                            Plotly.relayout(chartId, {
                                width: 1200,
                                autosize: true
                            });
                        });
                        
                        // 强制重新调整大小和重新布局
                        setTimeout(() => {
                            Plotly.relayout(chartId, {
                                width: 1200,
                                autosize: true
                            });
                        }, 100);
                        
                        // 再次确保图表完全适应容器
                        setTimeout(() => {
                            Plotly.relayout(chartId, {
                                width: 1200
                            });
                        }, 300);
                        
                        // 最终确保
                        setTimeout(() => {
                            Plotly.relayout(chartId, {
                                width: 1200
                            });
                        }, 500);
                    }, 100);
                } else if (type === 'error') {
                    contentDiv.innerHTML = `
                        <div class="flex items-center space-x-2 mb-2">
                            <svg class="w-5 h-5 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                            </svg>
                            <span class="text-sm font-medium">处理错误</span>
                        </div>
                        <div class="whitespace-pre-wrap">${this.escapeHtml(content)}</div>
                    `;
                }

                messageContainer.appendChild(headerDiv);
                messageContainer.appendChild(contentDiv);
                messageDiv.appendChild(messageContainer);
                
                // 添加淡入动画
                messageDiv.style.opacity = '0';
                messageDiv.style.transform = 'translateY(10px)';
                messageDiv.style.transition = 'all 0.3s ease-out';
                
                this.messagesContainer.appendChild(messageDiv);
                
                // 触发动画
                setTimeout(() => {
                    messageDiv.style.opacity = '1';
                    messageDiv.style.transform = 'translateY(0)';
                }, 50);
                
                // 绑定事件监听器
                this.bindMessageEvents(messageDiv);
                
                // 滚动到底部
                this.scrollToBottom();
            }

            scrollToBottom() {
                setTimeout(() => {
                    this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
                }, 50);
            }

            createTable(data) {
                if (!data || data.length === 0) {
                    return `
                        <div class="flex items-center mb-3">
                            <svg class="w-5 h-5 text-blue-600 dark:text-blue-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2h2a2 2 0 002-2z"></path>
                            </svg>
                            <span class="text-sm font-medium text-gray-700 dark:text-gray-300">查询结果</span>
                        </div>
                        <div class="text-center py-8 text-gray-500 dark:text-gray-400">
                            <svg class="w-12 h-12 mx-auto mb-2 text-gray-300 dark:text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"></path>
                            </svg>
                            <p>没有查询到数据</p>
                        </div>
                    `;
                }

                const headers = Object.keys(data[0]);
                const totalRows = data.length;
                const tableId = 'table_' + Date.now();

                return `
                    <div class="flex items-center justify-between mb-3">
                        <div class="flex items-center space-x-2">
                            <svg class="w-5 h-5 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2h2a2 2 0 002-2z"></path>
                            </svg>
                            <span class="text-sm font-medium text-gray-700 dark:text-gray-300">查询结果</span>
                            <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
                                ${totalRows} 行
                            </span>
                        </div>
                        <div class="flex items-center space-x-2">
                            <button class="export-table-btn text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 flex items-center space-x-1" data-table-id="${tableId}">
                                 <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                     <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
                                 </svg>
                                 <span>导出</span>
                             </button>
                        </div>
                    </div>
                    <div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden shadow-sm">
                        <div class="max-h-96 overflow-auto" id="${tableId}">
                            <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
                                <thead class="bg-gray-50 dark:bg-gray-800 sticky top-0">
                                    <tr>
                                        ${headers.map(header => `
                                            <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider border-r border-gray-200 dark:border-gray-700 last:border-r-0">
                                                <div class="flex items-center space-x-1">
                                                    <span>${this.escapeHtml(header)}</span>
                                                </div>
                                            </th>
                                        `).join('')}
                                    </tr>
                                </thead>
                                <tbody class="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
                                    ${data.map((row, index) => `
                                        <tr class="hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors ${index % 2 === 0 ? 'bg-gray-50/30 dark:bg-gray-800/30' : ''}">
                                            ${headers.map(header => {
                                                const cellValue = String(row[header] || '');
                                                const isLongText = cellValue.length > 50;
                                                const isNumber = !isNaN(cellValue) && cellValue !== '';
                                                return `
                                                    <td class="px-4 py-3 text-sm border-r border-gray-200 dark:border-gray-700 last:border-r-0 ${isNumber ? 'text-right font-mono' : 'text-left'} text-gray-900 dark:text-gray-100">
                                                        ${isLongText ? 
                                                            `<div class="max-w-xs truncate" title="${this.escapeHtml(cellValue)}">${this.escapeHtml(cellValue)}</div>` : 
                                                            `<span class="${isNumber ? 'font-mono' : ''}">${this.escapeHtml(cellValue)}</span>`
                                                        }
                                                    </td>
                                                `;
                                            }).join('')}
                                        </tr>
                                    `).join('')}
                                </tbody>
                            </table>
                        </div>
                    </div>
                `;
            }

            escapeHtml(text) {
                const div = document.createElement('div');
                div.textContent = text;
                return div.innerHTML;
            }

            updateSendButton(loading) {
                this.sendBtn.disabled = loading;
                if (loading) {
                    this.sendBtn.innerHTML = `
                        <svg class="animate-spin w-5 h-5" fill="none" viewBox="0 0 24 24">
                            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                        </svg>
                    `;
                } else {
                    this.sendBtn.innerHTML = `
                        <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
                        </svg>
                    `;
                }
            }

            startNewChat() {
                this.currentChatId = null;
                this.messagesContainer.innerHTML = `
                    <div class="text-center text-gray-500 dark:text-gray-400 mt-20">
                        <svg class="w-16 h-16 mx-auto mb-4 text-gray-300 dark:text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
                        </svg>
                        <p class="text-lg font-medium">开始新的对话</p>
                        <p class="text-sm">输入您的问题，我将为您生成SQL查询并执行</p>
                    </div>
                `;
            }

            async loadChatHistory() {
                try {
                    const response = await authenticatedFetch('/api/v0/get_question_history');
                    const data = await response.json();
                    
                    if (data.type === 'question_history') {
                        this.renderChatHistory(data.questions);
                    }
                } catch (error) {
                    console.error('加载历史记录失败:', error);
                }
            }

            renderChatHistory(questions) {
                this.chatHistory.innerHTML = '';
                
                questions.slice(0, 10).forEach(item => {
                    const historyItem = document.createElement('div');
                    historyItem.className = 'p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer text-sm text-gray-700 dark:text-gray-300 truncate';
                    historyItem.textContent = item.question;
                    historyItem.addEventListener('click', () => this.loadQuestion(item.id));
                    this.chatHistory.appendChild(historyItem);
                });
            }

            async loadQuestion(id) {
                try {
                    const response = await authenticatedFetch(`/api/v0/load_question?id=${id}`);
                    const data = await response.json();
                    
                    if (data.type === 'question_cache') {
                        this.currentChatId = id;
                        this.messagesContainer.innerHTML = '';
                        
                        this.addMessage('user', data.question);
                        this.addMessage('sql', data.sql);
                        
                        const df = JSON.parse(data.df);
                        this.addMessage('table', df);
                        
                        if (data.fig && data.fig !== '{}') {
                            this.addMessage('chart', JSON.parse(data.fig));
                        }
                    }
                } catch (error) {
                    console.error('加载问题失败:', error);
                }
            }

            // 复制到剪贴板功能
            copyToClipboard(text) {
                if (navigator.clipboard && window.isSecureContext) {
                    navigator.clipboard.writeText(text).then(() => {
                        this.showToast('已复制到剪贴板', 'success');
                    }).catch(err => {
                        console.error('复制失败:', err);
                        this.fallbackCopyTextToClipboard(text);
                    });
                } else {
                    this.fallbackCopyTextToClipboard(text);
                }
            }

            // 备用复制方法
            fallbackCopyTextToClipboard(text) {
                const textArea = document.createElement('textarea');
                textArea.value = text;
                textArea.style.top = '0';
                textArea.style.left = '0';
                textArea.style.position = 'fixed';
                document.body.appendChild(textArea);
                textArea.focus();
                textArea.select();
                try {
                    document.execCommand('copy');
                    this.showToast('已复制到剪贴板', 'success');
                } catch (err) {
                    console.error('复制失败:', err);
                    this.showToast('复制失败', 'error');
                }
                document.body.removeChild(textArea);
            }

            // 导出表格数据
            exportTableData(tableId) {
                const table = document.getElementById(tableId);
                if (!table) return;
                
                const rows = table.querySelectorAll('tr');
                let csvContent = '';
                
                rows.forEach(row => {
                    const cols = row.querySelectorAll('th, td');
                    const rowData = Array.from(cols).map(col => {
                        let text = col.textContent.trim();
                        // 处理包含逗号的数据
                        if (text.includes(',')) {
                            text = `"${text}"`;
                        }
                        return text;
                    });
                    csvContent += rowData.join(',') + '\n';
                });
                
                // 创建下载链接
                const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
                const link = document.createElement('a');
                const url = URL.createObjectURL(blob);
                link.setAttribute('href', url);
                link.setAttribute('download', `查询结果_${new Date().toISOString().slice(0, 10)}.csv`);
                link.style.visibility = 'hidden';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                
                this.showToast('数据已导出', 'success');
            }

            // 添加加载指示器
            addLoadingMessage() {
                const loadingId = 'loading-' + Date.now();
                const messageDiv = document.createElement('div');
                messageDiv.id = loadingId;
                messageDiv.className = 'flex items-start space-x-3 mb-4 animate-pulse';
                
                messageDiv.innerHTML = `
                    <div class="flex-shrink-0">
                        <div class="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
                            <svg class="w-4 h-4 text-white animate-spin" fill="none" viewBox="0 0 24 24">
                                <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                            </svg>
                        </div>
                    </div>
                    <div class="flex-1 bg-gray-100 dark:bg-gray-700 rounded-lg p-3">
                        <div class="flex items-center space-x-2">
                            <div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div>
                            <div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style="animation-delay: 0.1s"></div>
                            <div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
                            <span class="text-sm text-gray-600 dark:text-gray-300 ml-2">正在思考...</span>
                        </div>
                    </div>
                `;
                
                this.messagesContainer.appendChild(messageDiv);
                this.scrollToBottom();
                
                return loadingId;
            }
            
            // 移除加载指示器
            removeLoadingMessage(loadingId) {
                const loadingElement = document.getElementById(loadingId);
                if (loadingElement) {
                    loadingElement.remove();
                }
            }

            // 绑定消息事件
            bindMessageEvents(messageDiv) {
                // 绑定SQL复制按钮
                const copySqlBtn = messageDiv.querySelector('.copy-sql-btn');
                if (copySqlBtn) {
                    copySqlBtn.addEventListener('click', () => {
                        const sql = copySqlBtn.getAttribute('data-sql');
                        this.copyToClipboard(sql);
                    });
                }
                
                // 绑定表格导出按钮
                const exportTableBtn = messageDiv.querySelector('.export-table-btn');
                if (exportTableBtn) {
                    exportTableBtn.addEventListener('click', () => {
                        const tableId = exportTableBtn.getAttribute('data-table-id');
                        this.exportTableData(tableId);
                    });
                }
                
                // 绑定保存图表按钮
                const saveChartBtn = messageDiv.querySelector('.save-chart-btn');
                if (saveChartBtn) {
                    saveChartBtn.addEventListener('click', () => {
                        const chartId = saveChartBtn.getAttribute('data-chart-id');
                        const chartData = saveChartBtn.getAttribute('data-chart-data');
                        this.saveChartToDashboard(chartId, chartData);
                    });
                }
                
                // 绑定图表下载按钮
                const chartDownloadBtn = messageDiv.querySelector('.chart-download-btn');
                if (chartDownloadBtn) {
                    chartDownloadBtn.addEventListener('click', () => {
                        const chartId = chartDownloadBtn.getAttribute('data-chart-id');
                        this.downloadChart(chartId);
                    });
                }
            }


            // 保存图表到仪表板
            async saveChartToDashboard(chartId, chartDataStr) {
                try {
                    // 解析图表数据
                    const chartData = JSON.parse(chartDataStr.replace(/&apos;/g, "'"));
                    
                    // 获取当前问题和SQL（如果有的话）
                    const question = this.getCurrentQuestion();
                    const sql = this.getCurrentSQL();
                    
                    // 弹出对话框让用户输入图表标题
                    const title = prompt('请输入图表标题:', `图表_${new Date().toLocaleString()}`);
                    if (!title) {
                        return; // 用户取消了
                    }
                    
                    // 保存图表
                    const response = await authenticatedFetch('/api/v0/charts', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            title: title,
                            chart_type: 'plotly',
                            chart_data: JSON.stringify(chartData),
                            question: question,
                            sql: sql
                        })
                    });
                    
                    const data = await response.json();
                    
                    if (data.type === 'success') {
                        this.showToast('图表保存成功！', 'success');
                        
                        // 询问是否跳转到仪表板
                        if (confirm('图表已保存成功！是否跳转到仪表板页面？')) {
                            window.open('/static/dashboard.html', '_blank');
                        }
                    } else {
                        this.showToast('保存图表失败: ' + data.error, 'error');
                    }
                } catch (error) {
                    console.error('保存图表失败:', error);
                    this.showToast('保存图表失败', 'error');
                }
            }
            
            // 获取当前问题
            getCurrentQuestion() {
                const userMessages = this.messagesContainer.querySelectorAll('.justify-end');
                if (userMessages.length > 0) {
                    const lastUserMessage = userMessages[userMessages.length - 1];
                    const messageContent = lastUserMessage.querySelector('.whitespace-pre-wrap');
                    return messageContent ? messageContent.textContent.trim() : '';
                }
                return '';
            }
            
            // 获取当前SQL
            getCurrentSQL() {
                const sqlMessages = this.messagesContainer.querySelectorAll('.copy-sql-btn');
                if (sqlMessages.length > 0) {
                    const lastSqlMessage = sqlMessages[sqlMessages.length - 1];
                    return lastSqlMessage.getAttribute('data-sql') || '';
                }
                return '';
            }

            // 下载图表
            downloadChart(chartId) {
                const chartElement = document.getElementById(chartId);
                if (chartElement) {
                    Plotly.downloadImage(chartElement, {
                        format: 'png',
                        width: 1200,
                        height: 800,
                        filename: `chart_${new Date().getTime()}`
                    }).then(() => {
                        this.showToast('图表下载成功', 'success');
                    }).catch(() => {
                        this.showToast('图表下载失败', 'error');
                    });
                }
            }

            // 显示提示消息
            showToast(message, type = 'info') {
                const toast = document.createElement('div');
                toast.className = `fixed top-20 right-4 z-50 px-4 py-2 rounded-lg shadow-lg text-white text-sm font-medium transition-all duration-300 transform translate-x-full ${
                    type === 'success' ? 'bg-green-600' : 
                    type === 'error' ? 'bg-red-600' : 
                    'bg-blue-600'
                }`;
                toast.textContent = message;
                
                document.body.appendChild(toast);
                
                // 显示动画
                setTimeout(() => {
                    toast.classList.remove('translate-x-full');
                }, 100);
                
                // 自动隐藏
                setTimeout(() => {
                    toast.classList.add('translate-x-full');
                    setTimeout(() => {
                        if (document.body.contains(toast)) {
                            document.body.removeChild(toast);
                        }
                    }, 300);
                }, 3000);
            }
        }

        // 初始化应用
        document.addEventListener('DOMContentLoaded', () => {
            new ChatApp();
        });
    </script>
</body>
</html>